#!/usr/bin/env python
# -*- coding: utf-8 -*-

"""
MES数据接收服务
用于接收生产线客户端发送的产品信息和心跳信号
API: http://10.168.1.200:6666/api/mes_data
"""

import os
import json
import time
import logging
import sqlite3
from datetime import datetime
from flask import Flask, request, jsonify
from flask_cors import CORS
from logging.handlers import RotatingFileHandler

# 创建应用实例
app = Flask(__name__)
CORS(app)  # 启用跨域支持

# 配置
class Config:
    # 数据库配置
    DATABASE = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'mes_data.db')
    # 日志配置
    LOG_DIR = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'logs')
    LOG_FILE = os.path.join(LOG_DIR, 'mes_server.log')
    LOG_LEVEL = logging.INFO
    # 服务配置
    HOST = '0.0.0.0'  # 监听所有网络接口
    PORT = 6666
    DEBUG = False

app.config.from_object(Config)

# 确保日志目录存在
if not os.path.exists(Config.LOG_DIR):
    os.makedirs(Config.LOG_DIR)

# 配置日志
handler = RotatingFileHandler(Config.LOG_FILE, maxBytes=10485760, backupCount=10, encoding='utf-8')
handler.setFormatter(logging.Formatter(
    '%(asctime)s %(levelname)s: %(message)s [in %(pathname)s:%(lineno)d]'
))
handler.setLevel(Config.LOG_LEVEL)
app.logger.addHandler(handler)
app.logger.setLevel(Config.LOG_LEVEL)

# 添加控制台日志
console_handler = logging.StreamHandler()
console_handler.setFormatter(logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s'))
app.logger.addHandler(console_handler)

# 设置标准输出编码
import sys
sys.stdout.reconfigure(encoding='utf-8')
sys.stderr.reconfigure(encoding='utf-8')

app.logger.info('MES数据接收服务启动')

# 初始化数据库
def init_db():
    """初始化数据库，创建必要的表"""
    conn = sqlite3.connect(Config.DATABASE)
    cursor = conn.cursor()

    # 创建产品数据表
    cursor.execute('''
    CREATE TABLE IF NOT EXISTS product_data (
        id INTEGER PRIMARY KEY AUTOINCREMENT,
        device_id TEXT NOT NULL,
        product_id TEXT NOT NULL,
        product_type TEXT,
        length REAL,
        width REAL,
        speed REAL,
        quality_score INTEGER,
        timestamp TEXT NOT NULL,
        received_at TEXT NOT NULL
    )
    ''')

    # 创建心跳数据表
    cursor.execute('''
    CREATE TABLE IF NOT EXISTS heartbeat_data (
        id INTEGER PRIMARY KEY AUTOINCREMENT,
        device_id TEXT NOT NULL,
        status TEXT NOT NULL,
        operator_id TEXT,
        shift_type TEXT,
        timestamp TEXT NOT NULL,
        received_at TEXT NOT NULL
    )
    ''')

    # 创建设备状态表
    cursor.execute('''
    CREATE TABLE IF NOT EXISTS device_status (
        device_id TEXT PRIMARY KEY,
        status TEXT NOT NULL,
        last_heartbeat TEXT NOT NULL,
        operator_id TEXT,
        shift_type TEXT,
        updated_at TEXT NOT NULL
    )
    ''')

    conn.commit()
    conn.close()
    app.logger.info('数据库初始化完成')

# 数据库操作函数
def get_db_connection():
    """获取数据库连接"""
    conn = sqlite3.connect(Config.DATABASE)
    conn.row_factory = sqlite3.Row  # 使结果以字典形式返回
    return conn

def save_product_data(data):
    """保存产品数据"""
    conn = get_db_connection()
    cursor = conn.cursor()

    now = datetime.now().isoformat()

    cursor.execute('''
    INSERT INTO product_data
    (device_id, product_id, product_type, length, width, speed, quality_score, timestamp, received_at)
    VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
    ''', (
        data.get('device_id'),
        data.get('product_id'),
        data.get('product_type'),
        data.get('length'),
        data.get('width'),
        data.get('speed'),
        data.get('quality_score'),
        data.get('timestamp', now),
        now
    ))

    conn.commit()
    conn.close()
    app.logger.info(f'保存产品数据: {data.get("product_id")} 来自设备: {data.get("device_id")}')

def save_heartbeat_data(data):
    """保存心跳数据并更新设备状态"""
    conn = get_db_connection()
    cursor = conn.cursor()

    now = datetime.now().isoformat()

    # 保存心跳数据
    cursor.execute('''
    INSERT INTO heartbeat_data
    (device_id, status, operator_id, shift_type, timestamp, received_at)
    VALUES (?, ?, ?, ?, ?, ?)
    ''', (
        data.get('device_id'),
        data.get('status', 'online'),
        data.get('operator_id'),
        data.get('shift_type'),
        data.get('timestamp', now),
        now
    ))

    # 更新设备状态
    cursor.execute('''
    INSERT OR REPLACE INTO device_status
    (device_id, status, last_heartbeat, operator_id, shift_type, updated_at)
    VALUES (?, ?, ?, ?, ?, ?)
    ''', (
        data.get('device_id'),
        data.get('status', 'online'),
        now,
        data.get('operator_id'),
        data.get('shift_type'),
        now
    ))

    conn.commit()
    conn.close()
    app.logger.info(f'保存心跳数据: 设备: {data.get("device_id")} 状态: {data.get("status", "online")}')

def get_all_devices():
    """获取所有设备状态"""
    conn = get_db_connection()
    cursor = conn.cursor()

    cursor.execute('SELECT * FROM device_status')
    devices = [dict(row) for row in cursor.fetchall()]

    conn.close()
    return devices

def check_offline_devices():
    """检查离线设备（超过5分钟没有心跳的设备）"""
    conn = get_db_connection()
    cursor = conn.cursor()

    now = datetime.now()

    # 获取所有设备
    cursor.execute('SELECT * FROM device_status')
    devices = [dict(row) for row in cursor.fetchall()]

    for device in devices:
        last_heartbeat = datetime.fromisoformat(device['last_heartbeat'])
        # 如果超过5分钟没有心跳，标记为离线
        if (now - last_heartbeat).total_seconds() > 300:  # 5分钟 = 300秒
            cursor.execute('''
            UPDATE device_status
            SET status = 'offline', updated_at = ?
            WHERE device_id = ? AND status != 'offline'
            ''', (now.isoformat(), device['device_id']))
            app.logger.warning(f'设备离线: {device["device_id"]}')

    conn.commit()
    conn.close()

# API路由
@app.route('/api/mes_data', methods=['POST'])
def receive_mes_data():
    """接收MES数据（产品信息或心跳信号）"""
    try:
        data = request.json

        if not data:
            return jsonify({'status': 'error', 'message': '无效的数据格式'}), 400

        # 记录原始数据
        app.logger.debug(f'接收到数据: {json.dumps(data, ensure_ascii=False)}')

        # 检查数据类型
        data_type = data.get('type')

        if data_type == 'product':
            # 产品数据
            save_product_data(data)
        elif data_type == 'heartbeat':
            # 心跳数据
            save_heartbeat_data(data)
        else:
            # 未知数据类型
            app.logger.warning(f'未知数据类型: {data_type}')
            return jsonify({'status': 'error', 'message': f'未知数据类型: {data_type}'}), 400

        return jsonify({'status': 'success', 'message': '数据接收成功'}), 200

    except Exception as e:
        app.logger.error(f'处理数据时出错: {str(e)}', exc_info=True)
        return jsonify({'status': 'error', 'message': f'服务器错误: {str(e)}'}), 500

@app.route('/api/devices', methods=['GET'])
def get_devices():
    """获取所有设备状态"""
    try:
        # 检查离线设备
        check_offline_devices()

        # 获取所有设备
        devices = get_all_devices()

        return jsonify({
            'status': 'success',
            'data': devices,
            'count': len(devices),
            'timestamp': datetime.now().isoformat()
        }), 200

    except Exception as e:
        app.logger.error(f'获取设备状态时出错: {str(e)}', exc_info=True)
        return jsonify({'status': 'error', 'message': f'服务器错误: {str(e)}'}), 500

@app.route('/api/status', methods=['GET'])
def get_status():
    """获取服务状态"""
    try:
        conn = get_db_connection()
        cursor = conn.cursor()

        # 获取产品数据数量
        cursor.execute('SELECT COUNT(*) as count FROM product_data')
        product_count = cursor.fetchone()['count']

        # 获取心跳数据数量
        cursor.execute('SELECT COUNT(*) as count FROM heartbeat_data')
        heartbeat_count = cursor.fetchone()['count']

        # 获取设备数量
        cursor.execute('SELECT COUNT(*) as count FROM device_status')
        device_count = cursor.fetchone()['count']

        # 获取在线设备数量
        cursor.execute("SELECT COUNT(*) as count FROM device_status WHERE status = 'online'")
        online_count = cursor.fetchone()['count']

        conn.close()

        return jsonify({
            'status': 'success',
            'data': {
                'product_count': product_count,
                'heartbeat_count': heartbeat_count,
                'device_count': device_count,
                'online_count': online_count,
                'server_time': datetime.now().isoformat(),
                'uptime': time.time() - start_time
            }
        }), 200

    except Exception as e:
        app.logger.error(f'获取服务状态时出错: {str(e)}', exc_info=True)
        return jsonify({'status': 'error', 'message': f'服务器错误: {str(e)}'}), 500

# 记录启动时间
start_time = time.time()

# 初始化数据库
init_db()

if __name__ == '__main__':
    app.run(host=Config.HOST, port=Config.PORT, debug=Config.DEBUG)
